home *** CD-ROM | disk | FTP | other *** search
/ Programming an RTS Game with Direct3D / Programming an RTS Game with Direct3D.iso / Examples / Chapter 5 / Example 5.4 / app.cpp next >
Encoding:
C/C++ Source or Header  |  2006-08-01  |  10.2 KB  |  374 lines

  1. //////////////////////////////////////////////////////////////
  2. // Example 5.4: RTS Unit Selection Example                    //
  3. // Written by: C. Granberg, 2005                            //
  4. //////////////////////////////////////////////////////////////
  5.  
  6. #include <windows.h>
  7. #include <d3dx9.h>
  8. #include <vector>
  9. #include "debug.h"
  10. #include "mouse.h"
  11. #include "object.h"
  12. #include "camera.h"
  13.  
  14. class APPLICATION
  15. {
  16.     public:
  17.         
  18.         APPLICATION();
  19.         HRESULT Init(HINSTANCE hInstance, int width, int height, bool windowed);
  20.         HRESULT Update(float deltaTime);
  21.         HRESULT Render();
  22.         HRESULT Cleanup();
  23.         HRESULT Quit();
  24.  
  25.         void Select();
  26.         int GetGnome();
  27.  
  28.     private:
  29.         IDirect3DDevice9* m_pDevice; 
  30.         std::vector<OBJECT> m_gnomes;
  31.         MOUSE m_mouse;
  32.         CAMERA m_camera;
  33.  
  34.         ID3DXLine *m_pLine;
  35.         D3DLIGHT9 m_light;
  36.         bool m_areaSelect;
  37.         INTPOINT m_startSel;
  38.         HWND m_mainWindow;
  39.         ID3DXFont *m_pFont, *m_pFontMouse;
  40. };
  41.  
  42. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance, PSTR cmdLine, int showCmd)
  43. {
  44.     APPLICATION app;
  45.  
  46.     if(FAILED(app.Init(hInstance, 800, 600, true)))
  47.         return 0;
  48.  
  49.     MSG msg;
  50.     memset(&msg, 0, sizeof(MSG));
  51.     int startTime = timeGetTime(); 
  52.  
  53.     while(msg.message != WM_QUIT)
  54.     {
  55.         if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  56.         {
  57.             ::TranslateMessage(&msg);
  58.             ::DispatchMessage(&msg);
  59.         }
  60.         else
  61.         {    
  62.             int t = timeGetTime();
  63.             float deltaTime = (t - startTime)*0.001f;
  64.  
  65.             app.Update(deltaTime);
  66.             app.Render();
  67.  
  68.             startTime = t;
  69.         }
  70.     }
  71.  
  72.     app.Cleanup();
  73.  
  74.     return msg.wParam;
  75. }
  76.  
  77. APPLICATION::APPLICATION()
  78. {
  79.     m_pDevice = NULL; 
  80.     m_mainWindow = 0;
  81.     m_pFont = NULL;
  82.     m_areaSelect = false;
  83.     m_pLine = NULL;
  84.  
  85.     srand(GetTickCount());
  86. }
  87.  
  88. HRESULT APPLICATION::Init(HINSTANCE hInstance, int width, int height, bool windowed)
  89. {
  90.     debug.Print("Application initiated");
  91.  
  92.     //Create Window Class
  93.     WNDCLASS wc;
  94.     memset(&wc, 0, sizeof(WNDCLASS));
  95.     wc.style         = CS_HREDRAW | CS_VREDRAW;
  96.     wc.lpfnWndProc   = (WNDPROC)::DefWindowProc; 
  97.     wc.hInstance     = hInstance;
  98.     wc.lpszClassName = "D3DWND";
  99.  
  100.     //Register Class and Create new Window
  101.     RegisterClass(&wc);
  102.     m_mainWindow = CreateWindow("D3DWND", "Example 5.4: RTS Unit Selection Example", WS_EX_TOPMOST, 0, 0, width, height, 0, 0, hInstance, 0); 
  103.     SetCursor(NULL);
  104.     ShowWindow(m_mainWindow, SW_SHOW);
  105.     UpdateWindow(m_mainWindow);
  106.  
  107.     //Create IDirect3D9 Interface
  108.     IDirect3D9* d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
  109.  
  110.     if(d3d9 == NULL)
  111.     {
  112.         debug.Print("Direct3DCreate9() - FAILED");
  113.         return E_FAIL;
  114.     }
  115.  
  116.     //Check that the Device supports what we need from it
  117.     D3DCAPS9 caps;
  118.     d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
  119.  
  120.     //Hardware Vertex Processing or not?
  121.     int vp = 0;
  122.     if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
  123.         vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  124.     else vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  125.  
  126.     //Check vertex & pixelshader versions
  127.     if(caps.VertexShaderVersion < D3DVS_VERSION(2, 0) || caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
  128.     {
  129.         debug.Print("Warning - Your graphic card does not support vertex and pixelshaders version 2.0");
  130.     }
  131.  
  132.     //Set D3DPRESENT_PARAMETERS
  133.     D3DPRESENT_PARAMETERS d3dpp;
  134.     d3dpp.BackBufferWidth            = width;
  135.     d3dpp.BackBufferHeight           = height;
  136.     d3dpp.BackBufferFormat           = D3DFMT_A8R8G8B8;
  137.     d3dpp.BackBufferCount            = 1;
  138.     d3dpp.MultiSampleType            = D3DMULTISAMPLE_NONE;
  139.     d3dpp.MultiSampleQuality         = 0;
  140.     d3dpp.SwapEffect                 = D3DSWAPEFFECT_DISCARD; 
  141.     d3dpp.hDeviceWindow              = m_mainWindow;
  142.     d3dpp.Windowed                   = windowed;
  143.     d3dpp.EnableAutoDepthStencil     = true; 
  144.     d3dpp.AutoDepthStencilFormat     = D3DFMT_D24S8;
  145.     d3dpp.Flags                      = 0;
  146.     d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
  147.     d3dpp.PresentationInterval       = D3DPRESENT_INTERVAL_IMMEDIATE;
  148.  
  149.     //Create the IDirect3DDevice9
  150.     if(FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_mainWindow,
  151.                                  vp, &d3dpp, &m_pDevice)))
  152.     {
  153.         debug.Print("Failed to create IDirect3DDevice9");
  154.         return E_FAIL;
  155.     }
  156.  
  157.     //Release IDirect3D9 interface
  158.     d3d9->Release();
  159.  
  160.     D3DXCreateFont(m_pDevice, 18, 0, 0, 1, false,  
  161.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  162.                    DEFAULT_PITCH | FF_DONTCARE, "Arial", &m_pFont);
  163.  
  164.     D3DXCreateFont(m_pDevice, 24, 0, 0, 1, false,  
  165.                    DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
  166.                    DEFAULT_PITCH | FF_DONTCARE, "Arial Black", &m_pFontMouse);
  167.  
  168.     //Create m_light
  169.     ::ZeroMemory(&m_light, sizeof(m_light));
  170.     m_light.Type      = D3DLIGHT_DIRECTIONAL;
  171.     m_light.Ambient   = D3DXCOLOR(0.5, 0.5, 0.5, 1.0f);
  172.     m_light.Diffuse   = D3DXCOLOR(0.9, 0.9, 0.9, 1.0f);
  173.     m_light.Specular  = D3DXCOLOR(0.5, 0.5, 0.5, 1.0f);
  174.     m_light.Direction = D3DXVECTOR3(0.0f, -1.0f, 0.0f);
  175.     m_pDevice->SetLight(0, &m_light);
  176.     m_pDevice->LightEnable(0, true);
  177.  
  178.     //Set sampler state
  179.     for(int i=0;i<4;i++)
  180.     {
  181.         m_pDevice->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  182.         m_pDevice->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  183.         m_pDevice->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_POINT);
  184.     }
  185.  
  186.     //Init camera
  187.     m_camera.Init(m_pDevice);
  188.  
  189.     //Load objects
  190.     LoadObjectResources(m_pDevice);
  191.  
  192.     //Create 2D Line
  193.     D3DXCreateLine(m_pDevice, &m_pLine);
  194.  
  195.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 0.0f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "Sgt. Salty"));
  196.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(2.0f, 0.0f, 0.0f), D3DXVECTOR3(0.0f, 0.6f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "Gnomad"));
  197.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(2.0f, 0.0f, 2.0f), D3DXVECTOR3(0.0f, 2.6f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "Mr Finch"));
  198.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(-3.0f, 0.0f, -4.0f), D3DXVECTOR3(0.0f, 1.6f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "Hanz"));
  199.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(-1.0f, 0.0f, 3.0f), D3DXVECTOR3(0.0f, -0.6f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "von Wunderbaum"));
  200.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(5.0f, 0.0f, -3.0f), D3DXVECTOR3(0.0f, -1.0f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "Iceman"));
  201.     m_gnomes.push_back(OBJECT(GNOME, D3DXVECTOR3(-6.0f, 0.0f, 5.0f), D3DXVECTOR3(0.0f, -1.6f, 0.0f), D3DXVECTOR3(0.3f, 0.3f, 0.3f), "!!!"));
  202.  
  203.     //Init mouse
  204.     m_mouse.InitMouse(m_pDevice, m_mainWindow);
  205.  
  206.     return S_OK;
  207. }
  208.  
  209. HRESULT APPLICATION::Update(float deltaTime)
  210. {
  211.     //Control camera
  212.     D3DXMATRIX  matWorld;
  213.     D3DXMatrixIdentity(&matWorld);
  214.     m_pDevice->SetTransform(D3DTS_WORLD, &matWorld);
  215.  
  216.     //Update mouse
  217.     m_mouse.Update();
  218.  
  219.     //Update camera
  220.     m_camera.Update(m_mouse, deltaTime);
  221.  
  222.     if(KEYDOWN(VK_ESCAPE))
  223.         Quit();
  224.  
  225.     return S_OK;
  226. }    
  227.  
  228. void APPLICATION::Select()
  229. {
  230.     try
  231.     {
  232.         if(m_mouse.ClickLeft())    // If the mouse button is pressed
  233.         {                
  234.             for(int i=0;i<m_gnomes.size();i++)    //Deselect all Objects
  235.                 m_gnomes[i].m_selected = false;
  236.  
  237.             if(!m_areaSelect)        // If no area selection is in progress
  238.             {    
  239.                 //GetGnome() returns a Gnome using the mouse ray. If no 
  240.                 // gnome is found this function returns -1
  241.                 int gnome = GetGnome();
  242.  
  243.                 if(gnome >= 0)
  244.                     m_gnomes[gnome].m_selected = true;
  245.                 else
  246.                 {
  247.                     m_areaSelect = true;        // if no gnome if found,                                             
  248.                     m_startSel = m_mouse;        // start area selection
  249.                 }
  250.             }
  251.             else                    //Area Selection in progress
  252.             {
  253.                 // Create area rectangle
  254.                 INTPOINT p1 = m_startSel, p2 = m_mouse;
  255.                 if(p1.x > p2.x){int temp = p2.x;p2.x = p1.x;p1.x = temp;}
  256.                 if(p1.y > p2.y){int temp = p2.y;p2.y = p1.y;p1.y = temp;}
  257.                 RECT selRect = {p1.x, p1.y, p2.x, p2.y};
  258.  
  259.                 //Draw selection rectangle
  260.                 D3DXVECTOR2 box[] = {D3DXVECTOR2(p1.x, p1.y), D3DXVECTOR2(p2.x, p1.y), 
  261.                                      D3DXVECTOR2(p2.x, p2.y), D3DXVECTOR2(p1.x, p2.y), 
  262.                                      D3DXVECTOR2(p1.x, p1.y)};
  263.  
  264.                 m_pLine->SetWidth(1.0f);
  265.                 m_pLine->Begin();
  266.                 m_pLine->Draw(box, 5, 0xffffffff);                
  267.                 m_pLine->End();
  268.  
  269.                 //Select any gnomes inside our rectangle
  270.                 for(int i=0;i<m_gnomes.size();i++)
  271.                 {
  272.                     INTPOINT p = GetScreenPos(m_gnomes[i].GetPosition(), m_pDevice);
  273.                     if(p.inRect(selRect))m_gnomes[i].m_selected = true;
  274.                 }
  275.             }
  276.         }
  277.         else if(m_areaSelect)        //Stop area selection
  278.             m_areaSelect = false;
  279.  
  280.     }
  281.     catch(...)
  282.     {
  283.         debug.Print("Error in APPLICATION::Select()");
  284.     }
  285. }
  286.  
  287. int APPLICATION::GetGnome()
  288. {
  289.     //Find best Gnome
  290.     int gnome = -1;
  291.     float bestDist = 100000.0f;
  292.     for(int i=0;i<m_gnomes.size();i++)
  293.     {        
  294.         m_pDevice->SetTransform(D3DTS_WORLD, &m_gnomes[i].m_meshInstance.GetWorldMatrix());
  295.         RAY ray = m_mouse.GetRay();
  296.         float dist = ray.Intersect(m_gnomes[i].m_meshInstance);
  297.  
  298.         if(dist >= 0.0f && dist < bestDist)
  299.         {
  300.             gnome = i;
  301.             bestDist = dist;
  302.         }
  303.     }
  304.  
  305.     return gnome;
  306. }
  307.  
  308.  
  309. HRESULT APPLICATION::Render()
  310. {
  311.     // Clear the viewport
  312.     m_pDevice->Clear(0L, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L );
  313.     
  314.     // Begin the scene 
  315.     if(SUCCEEDED(m_pDevice->BeginScene()))
  316.     {
  317.         for(int i=0;i<m_gnomes.size();i++)
  318.             m_gnomes[i].Render();
  319.  
  320.         for(int i=0;i<m_gnomes.size();i++)
  321.             m_gnomes[i].PaintSelected();
  322.  
  323.         int gnome = GetGnome();
  324.  
  325.         Select();
  326.  
  327.         //Write mouse text
  328.         if(gnome != -1)
  329.         {
  330.             RECT mr[] = {{m_mouse.x + 2, m_mouse.y + 24, 0, 0}, {m_mouse.x, m_mouse.y + 22, 0, 0}};
  331.             m_pFontMouse->DrawText(NULL, m_gnomes[gnome].m_name.c_str(), -1, &mr[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xff000000);
  332.             m_pFontMouse->DrawText(NULL, m_gnomes[gnome].m_name.c_str(), -1, &mr[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffff0000);
  333.         }
  334.  
  335.         RECT r[] = {{10, 10, 0, 0}, {10, 30, 0, 0}};
  336.         m_pFont->DrawText(NULL, "Mouse Wheel: Change Camera Radius", -1, &r[0], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffffffff);
  337.         m_pFont->DrawText(NULL, "Arrows: Change Camera Angle", -1, &r[1], DT_LEFT| DT_TOP | DT_NOCLIP, 0xffffffff);
  338.         
  339.         //Draw mouse
  340.         m_mouse.Paint();
  341.  
  342.         // End the scene.
  343.         m_pDevice->EndScene();
  344.         m_pDevice->Present(0, 0, 0, 0);
  345.     }
  346.  
  347.     return S_OK;
  348. }
  349.  
  350. HRESULT APPLICATION::Cleanup()
  351. {
  352.     try
  353.     {
  354.         m_pFont->Release();
  355.         m_pFontMouse->Release();
  356.  
  357.         m_gnomes.clear();
  358.  
  359.         m_pLine->Release();
  360.         m_pDevice->Release();
  361.  
  362.         debug.Print("Application terminated");
  363.     }
  364.     catch(...){}
  365.  
  366.     return S_OK;
  367. }
  368.  
  369. HRESULT APPLICATION::Quit()
  370. {
  371.     ::DestroyWindow(m_mainWindow);
  372.     ::PostQuitMessage(0);
  373.     return S_OK;
  374. }